#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<string>
#include<cstdio>
#include<cstdlib>
// void handler(int signo)
// {
//     std::cout<<"进程捕捉到了一个信号, 信号编号是: "<<signo<<std::endl;
//     //exit(0);
// }

static void Usage(const std::string& proc)
{
    std::cout<<"\nUsage: "<<proc<<" pid signo\n"<<std::endl;
}

void catchSig(int signo)
{
    std::cout<<"获取到一个信号, 信号编号是: "<<signo<<std::endl;
}
void test()
{
    signal(SIGFPE,catchSig);//会循环打印, 因为一个进程对一个信号的处理动作只能设置一种, 而现
    //在的处理动作为自定义动作 而这个自定义动作就是打印并没有终止进程
    while(true)
    {
        std::cout<<"我在运行中..."<<std::endl;
        sleep(1);
        int a = 10;
        a/=0;
    }
}

void test1()
{
    signal(SIGFPE,catchSig);
    int a = 10;
    a/=0;//就除了一次0,但是运行后还是会循环打印,os又是怎么知道我除以0了呢? 
    //因为CPU中有一个状态寄存器而状态寄存器中有一个溢出标志位除以0时
    //CPU会出现运算异常OS就会识别出这个异常然后OS就会向目标进程发送信号
    //收到信号不一定会引起进程退出, 没有退出就有可能还会被调度
    //CPU内部的寄存器只有一份, 但是寄存器当中的内容属于当前进程的上下文
    //但是我们没有能力修正这个问题(溢出标志位)
    //当进程被切换的时候, 就有无数次状态寄存器被保存和恢复的过程
    //所以每一次恢复的时候, 就让OS识别到了CPU内部的状态寄存器中的溢出标志位是1所以会循环打印
    while(true)
    {
        std::cout<<"我在运行中..."<<std::endl;
        sleep(1);
    }
}

void test2()
{
    //野指针异常
    signal(SIGSEGV,catchSig);//11号信号
    while(true)
    {
        std::cout<<"我在运行中..."<<std::endl;
        sleep(1);
        int* p = nullptr;
        *p = 100;//OS又是怎么知道野指针了呢
        //指针本质就是虚拟地址虚拟地址到物理地址转化是通过页表+MMU(MMU是集成在了CPU中的)
        //0号地址通过页表映射发现是不允许当前进程访问0号地址的
        //所以MMU这个硬件因为越界访问发生异常OS就识别到了
        //所以OS就把这个异常转化成为了11号信号
    }
}

void test3()
{
    alarm(1);
    //统计1S左右,我们的计算机能够将数据累计多少次
    int cnt = 0;
    while(true)
    {
        std::cout<<"cnt: "<<cnt++<<std::endl;//因为每次都有和外设交互所以慢点
    }
}

int cnt1 = 0;
void catchSig1(int signo)
{
    std::cout<<"获取到一个信号, 信号编号是: "<<cnt1<<std::endl;//仅仅就这一次
    //alarm(1);
}
void test4()
{
    signal(SIGALRM,catchSig1);
    alarm(1);
    while(true)
    {
        cnt1++;//因为没有和外设交互所以快
    }
}

void test5()
{
    while(true)
    {
        int a[10];
        a[10000] = 106;
    }
}

void test6()
{
    //只能被9号信号杀死其他的信号都杀死不了(包括热键)kill -9 ......
    //OS内是禁止对9号信号做捕捉的即便你手动做了系统也不会给你设置
    for(int signo = 1;signo <= 31;signo++)
    {
        signal(signo,catchSig);
    }
    while(true)
    {
        std::cout<<"我再运行: "<<getpid()<<std::endl;
        sleep(1);
    }
}
//./mysignal pid signo
int main(int argc,char* argv[])
{
    //test();
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    // int cnt = 0;
    // while(cnt <= 10)
    // {
    //     printf("cnt: %d\n",cnt++);
    //     sleep(1);
    //     if(cnt >= 5) abort();//给自己发送指定的信号(6)SIGABRT    kill(getpid(),SIGABRT)
    //     //if(cnt >= 5) raise(3);//kill(getpid(),signo);
    // }
    
    // if(argc != 3)
    // {
    //     Usage(argv[0]);
    //     exit(1);
    // }
    // pid_t pid = atoi(argv[1]);
    // int signo = atoi(argv[2]);
    // int n = kill(pid,signo);//kill可以向任意进程发送任意信号
    // if(n != 0)
    // {
    //     perror("kill");
    // }

    //signal(2,handler);
    //这里是signal函数的调用, 并不是handler的调用
    //仅仅是设置了对2号信号的捕捉方法，并不代表该方法被调用了
    //一般这个方法不会执行, 除非收到对应的信号!
    //但是ctrl+c并没有中止这个进程是因为我们把默认动作改成了自定义动作
    
    // while(true)
    // {
    //     std::cout<<"我是一个进程: "<<getpid()<<std::endl;
    //     sleep(1);
    // }
    return 0;
}